package com.ruoyi.system.service.impl;


import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.system.domain.TbDataPackage;
import com.ruoyi.system.domain.TbDeviceAppLogs;
import com.ruoyi.system.domain.TbDeviceApps;
import com.ruoyi.system.domain.TbDeviceDataPackageLogs;
import com.ruoyi.system.domain.vo.AppCatalogVersionInfo;
import com.ruoyi.system.domain.vo.DeviceInfoVO;
import com.ruoyi.system.domain.vo.DeviceStorageInfo;
import com.ruoyi.system.domain.vo.DownloadResult;

import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.IFileDownloadService;

import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Service
public class FileDownloadServiceImpl implements IFileDownloadService {


    @Autowired
    private TbDeviceMapper deviceMapper;

    @Autowired
    private TbAppCatalogMapper appCatalogMapper;

    @Autowired
    private TbDeviceAppsMapper deviceAppsMapper;

    @Autowired
    private TbDataPackageMapper dataPackageMapper;


    @Autowired
    private TbAppVersionMapper appVersionMapper;


    @Autowired
    private TbDeviceAppLogsMapper deviceAppLogMapper;


    @Autowired
    private TbDeviceDataPackagesMapper deviceDataPackagesMapper;


    @Autowired
    private TbDeviceDataPackageLogsMapper deviceDataPackageLogsMapper;


    @Value("${file.storage.package}")
    private String storagePath;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void download(String devSN, String filePath, HttpServletRequest request, HttpServletResponse response) throws IOException {

        try {
            DownloadResult result = new DownloadResult();
            result.setDevSN(devSN);
            result.setDownloadTime(new Date());

            // 1. 验证设备
            if (deviceMapper.validateDevice(devSN) == 0) {
                response.sendError(HttpStatus.BAD_REQUEST.value(), "设备不存在或没有注册或没有登记或没有在线!");
                return; // 立即返回
            }

            // 拼接文件在服务器中的全存储路径
            String fileFullPath = FilenameUtils.concat(storagePath, filePath);

            // 2. 查找应用版本信息
            AppCatalogVersionInfo appVersionInfo = appVersionMapper.findAppVersionByFilePath(fileFullPath);
            if (appVersionInfo == null) {
                response.sendError(HttpStatus.NOT_FOUND.value(), "应用不存在或已下架");
                return; // 立即返回
            }

            result.setAppVersionInfo(appVersionInfo);

            // 3. 更新下载次数
            appVersionMapper.updateDownloadCount(appVersionInfo.getId());

            // 3.1 验证应用版本对操作系统的要求是否满足
//            DeviceInfoVO vo = deviceMapper.selectByDeviceInfoSn(devSN);
//            if (vo.getOsVer() != null && vo.getOsVer().length() > 0) {
//                String deviceVersion = extractVersionNumber(vo.getOsVer());
//                String appVersion = extractVersionNumber(appVersionInfo.getOsRequirement());
//
//                if (deviceVersion != null && appVersion != null) {
//                    if (compareVersions(deviceVersion, appVersion) < 0) {
//                        response.sendError(HttpStatus.BAD_REQUEST.value(), "设备操作系统版本不符合要求");
//                        return; // 立即返回
//                    }
//                }
//            }

            // 4. 检查是否已安装相同版本
            if (deviceAppLogMapper.checkAlreadyInstalled(devSN, appVersionInfo.getPackageName(), appVersionInfo.getPackageVersioncode()) > 0) {
                response.sendError(HttpStatus.BAD_REQUEST.value(), "该版本应用已安装，无需重复安装");
                return; // 立即返回
            }

            // 5. 检查设备存储空间
//            DeviceStorageInfo storageInfo = deviceMapper.getDeviceFreeStorage(devSN);
//            if (storageInfo != null && storageInfo.getRomFree() != null && storageInfo.getRomFree() < appVersionInfo.getPackageSize() / 1024.0) {
//                String errorMsg = String.format("设备存储空间不足: 需要%.2fMB, 剩余%.2fGB",
//                        appVersionInfo.getPackageSize() / (1024.0 * 1024.0), storageInfo.getRomFree());
//                response.sendError(HttpStatus.BAD_REQUEST.value(), errorMsg);
//                return; // 立即返回
//            }

            // 6. 记录安装开始日志
//            TbDeviceAppLogs deviceAppLogs = createInstallLog(devSN, appVersionInfo);
//            deviceAppLogMapper.insertTbDeviceAppLogs(deviceAppLogs);
//            result.setDeviceAppLogs(deviceAppLogs);

            // 7. 构建文件路径和安全检查
            Path file = buildAndValidateFilePath(filePath);

            // 8. 设置文件下载响应头
            setupDownloadHeaders(response, appVersionInfo, file);

            // 9. 执行文件下载
            boolean downloadSuccess = executeFileDownload(file, request, response);

            if (downloadSuccess) {
                // 10. 下载成功，更新安装状态
             //   updateInstallSuccess(deviceAppLogs.getId());
                // 更新下载次数
                appVersionMapper.updateInstallDeviceCount(appVersionInfo.getId());
                // 更新设备内存使用情况
              //  deviceMapper.updateDeviceRomUsage(devSN, appVersionInfo.getPackageSize() / 1024);
                // 更新deviceApps数据
                //updateDeviceAppInstallRecord(appVersionInfo, devSN);

                result.setSuccess(true);
                result.setMessage("应用下载成功");

            } else {
                // 下载过程中可能被中断
               // updateInstallFailure(deviceAppLogs.getId(), "下载被中断");

                result.setSuccess(false);
                result.setMessage("下载被中断");

                // 通过response返回错误信息
                response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value(), "下载被中断");
                return; // 立即返回
            }

        } catch (Exception e) {
            response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value(), "下载失败: " + e.getMessage());
            return; // 立即返回
        }

    }

    @Override
    public void downloadDataPackage(String devSN, String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
        try {
            // 1. 验证设备
            if (deviceMapper.validateDevice(devSN) == 0) {
                response.sendError(HttpStatus.BAD_REQUEST.value(), "设备不存在或没有注册或没有登记或没有在线!");
                return; // 立即返回
            }

            // 拼接文件在服务器中的全存储路径
            String fileFullPath = FilenameUtils.concat(storagePath, fileName);
            //查询数据包信息
            TbDataPackage dataPackage = dataPackageMapper.selectDataPackageByPackageUrl(fileFullPath);
            if (dataPackage == null) {
                response.sendError(HttpStatus.NOT_FOUND.value(), "数据包不存在或已下架");
                return; // 立即返回
            }
            //更新下载次数
            dataPackageMapper.updateDownloadCount(dataPackage.getId());

            //验证数据包是否适配这个机型
            // 假设你先根据devSN查询到设备型号
            String deviceModel = deviceMapper.getDeviceModelBySn(devSN);

            if (StringUtils.isNotBlank(dataPackage.getApplicableModels()) &&
                    StringUtils.isNotBlank(deviceModel)) {

                List<String> applicableModels = Arrays.asList(
                        dataPackage.getApplicableModels().split(","));

                if (!applicableModels.contains(deviceModel)) {
                    response.sendError(HttpStatus.BAD_REQUEST.value(),
                            "数据包不支持此设备型号: " + deviceModel);
                    return;
                }
            }
            //该设备是否已经安装了相同版本的 数据包
            if (deviceDataPackageLogsMapper.checkAlreadyInstalled(devSN, dataPackage.getPackageName(), dataPackage.getPackageVersioncode()) > 0) {
                response.sendError(HttpStatus.BAD_REQUEST.value(), "该版本数据包已安装，无需重复安装");
            }

            // 5. 检查设备存储空间
            DeviceStorageInfo storageInfo = deviceMapper.getDeviceFreeStorage(devSN);
            if (storageInfo != null && storageInfo.getRomFree() != null && storageInfo.getRomFree() < dataPackage.getPackageSize() / 1024.0) {
                String errorMsg = String.format("设备存储空间不足: 需要%.2fMB, 剩余%.2fGB",
                        dataPackage.getPackageSize() / (1024.0 * 1024.0), storageInfo.getRomFree());
                response.sendError(HttpStatus.BAD_REQUEST.value(), errorMsg);
                return; // 立即返回
            }
            //5.1. 保存或者更新数据包安装记录
            //    deviceDataPackagesMapper.insertTbDeviceDataPackages(deviceDataPackages);


            // 6. 记录安装开始日志
            TbDeviceDataPackageLogs deviceDataPackageLogs = createInstallDataPackageLog(devSN, dataPackage);
            deviceDataPackageLogsMapper.insertTbDeviceDataPackageLogs(deviceDataPackageLogs);

            // 7. 构建文件路径和安全检查
            Path file = buildAndValidateFilePath(fileName);


        } catch (Exception e) {
            response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value(), "下载失败: " + e.getMessage());
        }
    }

    private TbDeviceDataPackageLogs createInstallDataPackageLog(String devSN, TbDataPackage dataPackage) {
        TbDeviceDataPackageLogs deviceDataPackageLogs = new TbDeviceDataPackageLogs();
        deviceDataPackageLogs.setDeviceSn(devSN);
        deviceDataPackageLogs.setPackageId(dataPackage.getId());
        deviceDataPackageLogs.setPackageName(dataPackage.getPackageName());
        deviceDataPackageLogs.setPackageVersioncode(dataPackage.getPackageVersioncode());
        deviceDataPackageLogs.setPackageVersionnumber(dataPackage.getPackageVersionnumber());
        deviceDataPackageLogs.setPackageType(dataPackage.getPackageType());
        deviceDataPackageLogs.setUpdateContent("");
        deviceDataPackageLogs.setUpdateStatus(0);
        deviceDataPackageLogs.setUpdateDate(new Date());
        deviceDataPackageLogs.setUpdateMethod(0);
        deviceDataPackageLogs.setErrorMessage("");
        deviceDataPackageLogs.setUpdateMethod(0);
        deviceDataPackageLogs.setCreateBy(SecurityUtils.getUsername());
        deviceDataPackageLogs.setCreateTime(new Date());
        return deviceDataPackageLogs;
    }


    private void updateDeviceAppInstallRecord(AppCatalogVersionInfo appVersionInfo, String devSN) {
        // 查询现有记录
        TbDeviceApps existingApp = deviceAppsMapper.selectByAppNameOrPackageName(
                appVersionInfo.getAppName(),
                appVersionInfo.getPackageName()
        );

        if (existingApp == null) {
            // 新增记录
            TbDeviceApps newDeviceApp = createNewDeviceApp(appVersionInfo, devSN);
            deviceAppsMapper.insertTbDeviceApps(newDeviceApp);
        } else {
            // 更新现有记录
            updateExistingDeviceApp(existingApp, appVersionInfo, devSN);
            deviceAppsMapper.updateTbDeviceApps(existingApp);
        }

    }

    /**
     * 创建新的设备应用记录
     */
    private TbDeviceApps createNewDeviceApp(AppCatalogVersionInfo appVersionInfo, String devSN) {
        TbDeviceApps deviceApp = new TbDeviceApps();
        deviceApp.setDeviceSn(devSN);
        deviceApp.setPackageName(appVersionInfo.getPackageName());
        deviceApp.setPackageVersioncode(appVersionInfo.getPackageVersioncode());
        deviceApp.setPackageVersionnumber(appVersionInfo.getPackageVersionnumber());
        deviceApp.setAppName(appVersionInfo.getAppName());
        deviceApp.setInstallDate(new Date());
        deviceApp.setIsSystemApp(1);
        deviceApp.setLastUpdateDate(new Date());
        deviceApp.setStatus(1);

        // 安全地获取用户名，避免空指针
        String username = SecurityUtils.getUsername();
        deviceApp.setCreateBy(username != null ? username : "system");
        deviceApp.setCreateTime(new Date());

        return deviceApp;
    }

    /**
     * 更新现有设备应用记录
     */
    private void updateExistingDeviceApp(TbDeviceApps existingApp,
                                         AppCatalogVersionInfo appVersionInfo,
                                         String devSN) {
        existingApp.setDeviceSn(devSN);
        existingApp.setPackageName(appVersionInfo.getPackageName());
        existingApp.setPackageVersioncode(appVersionInfo.getPackageVersioncode());
        existingApp.setPackageVersionnumber(appVersionInfo.getPackageVersionnumber());
        existingApp.setAppName(appVersionInfo.getAppName());
        existingApp.setInstallDate(new Date());
        existingApp.setLastUpdateDate(new Date());
        existingApp.setStatus(1);

        // 更新时不应该修改创建者和创建时间
        // 如果需要记录更新者，可以添加updateBy字段
    }

    // 比较版本号的通用方法
    private int compareVersions(String version1, String version2) {
        if (version1 == null && version2 == null) return 0;
        if (version1 == null) return -1;
        if (version2 == null) return 1;

        String[] v1Parts = version1.split("\\.");
        String[] v2Parts = version2.split("\\.");

        int length = Math.max(v1Parts.length, v2Parts.length);

        for (int i = 0; i < length; i++) {
            int v1 = (i < v1Parts.length) ? Integer.parseInt(v1Parts[i]) : 0;
            int v2 = (i < v2Parts.length) ? Integer.parseInt(v2Parts[i]) : 0;

            if (v1 != v2) {
                return v1 - v2;
            }
        }

        return 0;
    }


    // 提取纯版本号（如从"HarmonyOS 2.0.1"中提取"2.0.1"）
    private String extractVersionNumber(String osVersionStr) {
        if (osVersionStr == null) return null;

        // 匹配数字和点组成的版本号
        Pattern pattern = Pattern.compile("(\\d+(\\.\\d+)*)");
        Matcher matcher = pattern.matcher(osVersionStr);

        if (matcher.find()) {
            return matcher.group(1);
        }

        return null;
    }

    private TbDeviceAppLogs createInstallLog(String devSN, AppCatalogVersionInfo appVersionInfo) {
        TbDeviceAppLogs log = new TbDeviceAppLogs();
        log.setDeviceSn(devSN);
        log.setAppId(deviceAppLogMapper.findDeviceAppId(devSN, appVersionInfo.getPackageName()));
        log.setPackageName(appVersionInfo.getPackageName());
        log.setPackageVersioncode(appVersionInfo.getPackageVersioncode());
        log.setPackageVersionnumber(appVersionInfo.getPackageVersionnumber());
        log.setPackageContent(appVersionInfo.getRemark());
        log.setPackageStatus(0); // 开始安装
        log.setInstallDate(new Date());
        log.setInstallMethod(1); // OTA方式
        log.setCreateBy(SecurityUtils.getLoginUser().getUsername());
        return log;
    }


    private void updateInstallSuccess(Long installLogId) {
        if (installLogId != null) {
            deviceAppLogMapper.updateDeviceAppLogStatus(installLogId, 1, null);
        }
    }

    private void updateInstallFailure(Long installLogId, String errorMessage) {
        if (installLogId != null) {
            deviceAppLogMapper.updateDeviceAppLogStatus(installLogId, 0, errorMessage);
        }
    }


    private void setupDownloadHeaders(HttpServletResponse response,
                                      AppCatalogVersionInfo appVersionInfo,
                                      Path file) throws IOException {
        try {
            String fileName = getFileName(appVersionInfo);
            long fileLength = Files.size(file);

            // 基础头信息
            response.setContentType("application/vnd.android.package-archive");
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());

            // 简化文件名处理（大多数现代浏览器都支持UTF-8）
            String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString())
                    .replace("+", "%20");
            String contentDisposition = "attachment; filename=\"" + fileName + "\"; filename*=UTF-8''" + encodedFileName;

            response.setHeader("Content-Disposition", contentDisposition);
            response.setHeader("Content-Length", String.valueOf(fileLength));

            // 缓存控制
            response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Expires", "0");

            // 校验信息
            if (StringUtils.isNotBlank(appVersionInfo.getPackageHash())) {
                response.setHeader("Content-MD5", appVersionInfo.getPackageHash());
            }

            // 自定义头信息（用于状态追踪）
            response.setHeader("X-Download-Status", "success");
            response.setHeader("X-File-Name", fileName);
            response.setHeader("X-File-Size", String.valueOf(fileLength));
            response.setHeader("X-App-Name", appVersionInfo.getAppName());
            response.setHeader("X-App-Version", appVersionInfo.getPackageVersionnumber());

        } catch (Exception e) {
            throw new IOException("设置下载头信息失败", e);
        }
    }

    private boolean executeFileDownload(Path file, HttpServletRequest request, HttpServletResponse response) {
        try (InputStream inputStream = Files.newInputStream(file); OutputStream outputStream = response.getOutputStream()) {

            byte[] buffer = new byte[8192];
            int bytesRead;
            long totalBytesRead = 0;
            long fileLength = Files.size(file);

            // 处理断点续传
            String rangeHeader = request.getHeader("Range");
            if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
                String[] ranges = rangeHeader.substring(6).split("-");
                long start = Long.parseLong(ranges[0]);
                long end = ranges.length > 1 ? Long.parseLong(ranges[1]) : fileLength - 1;

                inputStream.skip(start);
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileLength);
                response.setHeader("Content-Length", String.valueOf(end - start + 1));

                long bytesToRead = end - start + 1;
                while (bytesToRead > 0 && (bytesRead = inputStream.read(buffer)) != -1) {
                    int bytesToWrite = (int) Math.min(bytesRead, bytesToRead);
                    outputStream.write(buffer, 0, bytesToWrite);
                    bytesToRead -= bytesToWrite;
                    totalBytesRead += bytesToWrite;
                }
            } else {
                // 完整下载
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                    totalBytesRead += bytesRead;
                }
            }

            outputStream.flush();
            return totalBytesRead > 0;

        } catch (Exception e) {
            return false;
        }
    }

    private DownloadResult handleDownloadException(Exception e, DownloadResult result, String devSN) {
        String errorMessage = getErrorMessage(e);
        result.setSuccess(false);
        result.setMessage(errorMessage);
        return result;
    }

    private String getFileName(AppCatalogVersionInfo appVersionInfo) {
        return appVersionInfo.getPackageName() + "_" + appVersionInfo.getPackageVersioncode() + ".hap";
    }

    private String getErrorMessage(Exception e) {
        if (e instanceof FileNotFoundException) {
            return "应用安装包不存在";
        } else if (e instanceof SecurityException) {
            return "非法文件访问权限";
        } else {
            return "系统内部错误: " + e.getMessage();
        }
    }

    private Path buildAndValidateFilePath(String filePath) throws IOException {
        Path file = Paths.get(storagePath, filePath).normalize();
        if (!file.startsWith(Paths.get(storagePath).normalize())) {
            throw new SecurityException("非法文件路径访问");
        }
//        if (!Files.exists(file) || !Files.isRegularFile(file)) {
//            throw new FileNotFoundException("文件不存在: " + filePath);
//        }
        return file;
    }
}
